from pd.const import *
from pd.struct import *
import random

class HistoryPlayer(Player):
    # memLength is length of the player's memory
    # strategy is a function that takes a CircularList and returns
    # the next move of the player
    def __init__(self, strat, memInitial):
        self.mem = CircularList(memInitial)
        self.strat = strat
  
    def reset(self):
        self.mem.reset()

    def move(self):
        return self.strat(self.mem)
    
    def tell(self, own, oth):
        self.mem.pushFront((own, oth))

def standardHistoryPlayer(name, memInitial):
    def ALLC(mem):
        return C
    
    def ALLD(mem):
        return D
    
    def GRIM(mem):
        for own, oth in mem:
            if own == D or oth == D: return D
        return C
    
    def PAVLOV(mem):
        netS = 0
        for own, oth in mem:
            if oth == own: netS += 1
            else: netS -= 1
        if netS < 0: return D
        return C
    
    def RAND(mem):
        return random.randint(0, 1) == 1
    
    def TFT(mem):
        if len(mem):
            if mem[0][1] == D: return D
        return C
    
    standards = {
        "allc" : ALLC,
        "alld" : ALLD,
        "grim" : GRIM,
        "pavlov" : PAVLOV,
        "rand" : RAND,
        "tft" : TFT,
        }
    
    name = name.lower()
    result = HistoryPlayer(standards[name], memInitial)
    result.name = name
    return result

# performs a strategy based on a lookup table encoded as a list
def lutHistoryPlayer(lut, memInitial):
    def strat(mem):
        idx = 0
        for own, oth in mem:
            idx << 2
            if own == C: idx += 1
            if oth == C: idx += 2
        return lut[idx % len(lut)]
    
    result = HistoryPlayer(strat, memInitial)
    result.name = "lut"
    return result


